package com.anyext.storage.lb;

import java.util.LinkedList;

public class LBRound<RoundResult> implements RoundCard<RoundResult> {

	private LinkedList<Holder<RoundResult>> hs = new LinkedList<Holder<RoundResult>>();

	private Object[] services = new Object[0];
	private int currentPos = 0;

	@Override
	public void add(RoundResult card, int lbfactor) {
		Holder<RoundResult> h = new Holder<RoundResult>();
		h.service = card;
		h.lbfactor = lbfactor;
		hs.add(h);
	}

	protected void prepareNGcd() {
		int[] facs = new int[hs.size()];

		for (int i = 0; i < hs.size(); i++) {
			Holder<RoundResult> h = hs.get(i);
			facs[i] = h.lbfactor;
		}

		int gcd = ngcd(facs);

		if (gcd > 1) {
			for (int i = 0; i < hs.size(); i++) {
				Holder<RoundResult> h = hs.get(i);
				h.lbfactor = h.lbfactor / gcd;
			}
		}
	}

	@Override
	public void apply() {
		prepareNGcd();

		// set up load balance base.
		double baseNum = 0;

		for (int i = 0; i < hs.size(); i++) {
			Holder<RoundResult> h = hs.get(i);

			// 设定范围，防止溢出。
			if (h.lbfactor < 1) {
				h.lbfactor = 1;
			} else if (h.lbfactor > 10000) {
				h.lbfactor = 10000;
			}

			int fac = h.lbfactor;

			baseNum += fac;
		}

		Object[] lv = new Object[(int) baseNum];

		for (int i = 0; i < hs.size(); i++) {
			Holder<RoundResult> h = hs.get(i);

			Object service = h.service;
			int fac = h.lbfactor;

			if (i < hs.size() - 1) { // 不是最后一个DataSourceDescriptor
				double offset = baseNum / fac;

				for (int k = 0; k < fac; k++) {
					int pos = (int) (offset * k);
					pos += i;

					while (lv[pos] != null && pos < baseNum) {
						pos++;
					}

					if (pos < baseNum) { // 找到了空闲的位置
						lv[pos] = service;
					}
				}
			} else { // 最后一个DataSourceDescriptor填补所有空闲
				for (int k = 0; k < lv.length; k++) {
					if (lv[k] == null) {
						lv[k] = service;
					}
				}
			}
		}

		this.services = lv;
	}

	@SuppressWarnings("unchecked")
	public RoundResult getCard() {
		int maxSize = services.length;
		if (maxSize == 0) {
			return null;
		} else if (maxSize == 1) {
			return (RoundResult) services[0];
		}

		int pos = this.currentPos++;

		if (pos >= maxSize) {
			pos = pos % maxSize;
			this.currentPos = pos + 1;
		}

		return (RoundResult) services[pos];
	}

	// 计算最大约数，通过最大公约数缩写lv数组大小。
	protected int gcd(int a, int b) {
		if (a < b) {
			int c = a;
			a = b;
			b = c;
		}
		if (b == 0) {
			return a;
		} else {
			return gcd(b, a % b);
		}
	}

	protected int ngcd(int[] a) {
		return ngcd(a, a.length);
	}

	protected int ngcd(int[] a, int n) {
		if (n == 1) {
			return a[0];
		}
		return gcd(a[n - 1], ngcd(a, n - 1));
	}

	protected static class Holder<Service> {
		public Service service;
		public int lbfactor;
	}

}